#include "gameboard.h"
#include <iostream>
#include "keeptrack.h"
using namespace std;
#include "cli.h"
#include <conio.h>
#include <string>
#include <windows.h>
#include <mmsystem.h>
#include <fstream>
#pragma comment(lib,"winmm.lib")



Gameboard::Gameboard()
{
	clearBoard();
	drawTitleScreen();
	startGame();
	initializeColorMap();
}

void Gameboard::setPlayerNumber(int a_player)
{
	m_player = a_player;
}

int Gameboard::getPlayerNumber()
{
	return m_player;
}

void Gameboard::setInput(char a_input)
{	
	m_input = a_input;
}

char Gameboard::getInput()
{
	return m_input;
}

void Gameboard::setGameInput(char a_gameInput)
{
	m_gameInput = a_gameInput;
}

char Gameboard::getGameInput()
{
	return m_gameInput;
}
//		---			OUTPUT FUNCTIONS		---		//

void Gameboard::drawTitleScreen()
{
	//ifstream is;
	//is.open("TitleScreen.txt");        // open file

	//if(!is)
	//{
	//	printf("unable to read file. \n");
	//	exit(1);
	//}
	//
	//is >> m_width >> m_height;
	//is.ignore(1024, '\n');

	//char c = 0;
	////Allocating Memory for the 2dMap
	//	m_Map = new char *[m_height];
	//	for(int i = 0;i < m_height; ++i)
	//	{
	//		m_Map[i] = new char [m_width];
	//		for(int j = 0; c != '\n' &&  j < m_width; ++j)
	//		{
	//			if(is.good())
	//			{
	//				c = is.get();
	//				if(c != '\n' && c != '\r')
	//				{
	//					m_Map[i][j] = c;
	//					cout << c;
	//				}	
	//				
	//			}
	//		}
	//		is.ignore(1024, '\n'); //ignore the next 1024 char, or until after a '\n' char is read
	//	}
	//is.close();           // close file 
	//draws the title
	gotoxy(15,2);
	cout << " ****   ***   *   *  *   *  *****   ****  *****" << endl;
	gotoxy(15,3);
	cout << "*      *   *  **  *  **  *  *      *        *  " << endl;
	gotoxy(15,4);
	cout << "*      *   *  * * *  * * *  ***    *        *  " << endl;
	gotoxy(15,5);
	cout << "*      *   *  *  **  *  **  *      *        *  " << endl;
	gotoxy(15,6);
	cout << " ****   ***   *   *  *   *  *****   ****    *  " << endl;

	gotoxy(25,8);
	cout << "*****   ***   *   *  **** " << endl;
	gotoxy(25,9);
	cout << "*      *   *  *   *  *   *" << endl;
	gotoxy(25,10);
	cout << "***    *   *  *   *  **** " << endl;
	gotoxy(25,11);
	cout << "*      *   *  *   *  *  * " << endl;
	gotoxy(25,12);
	cout << "*       ***    ***   *   *" << endl;

	//draws the options between one player and two players
	gotoxy(30,15);
	cout << " Press '1' - ONE PLAYER" << endl;
	gotoxy(30,17);
	cout << " Press '2' - TWO PLAYERS" << endl;

	//draws the author's name
	gotoxy(30,21);
	cout << "       By" << endl;
	gotoxy(30,22);
	cout << " Earsell Lewis" << endl;
	setcolor((rand() % 16),COLOR_BLACK);
}

void Gameboard::clearBoard()
{
	// clears the board and shows the amount of empty spaces in each row
	for (int r = 0; r < BOARD_HEIGHT; r++)
	{
		for (int c = 0; c < BOARD_WIDTH; c++)
		{
			m_board[r][c] = '.';
		}
	}
}

void Gameboard::drawBoard()
{
	//draws the borders of the game board
	for (int y = 0; y < BOARD_HEIGHT; y++)
	{
		gotoxy(30,21+y);
		cout << "|       |" << endl;
	}
	gotoxy(31,21);

	//draws the actual game board
	for (int r = 0; r < BOARD_HEIGHT; r++)
	{
		for (int c = 0; c < BOARD_WIDTH; c++)
		{
			gotoxy(31+c,21+r);
			setcolor(m_colorMap[r][c],COLOR_BLACK);
			cout << m_board[r][c];
			setcolor(COLOR_WHITE, COLOR_BLACK);
		}
	}

	//draws the bottom border
	gotoxy(30,27);
	cout << "---------" << endl;
}

void Gameboard::initializeColorMap()
{
	//creates a black background for the game area
	for (int r = ZERO; r < BOARD_HEIGHT; r++)
	{
		for (int c = ZERO; c < BOARD_WIDTH; c++)
		{
			if(m_board[r][c] != piece.getSymbol())
			{
				m_colorMap[r][c] = COLOR_GRAY;
			}
		}
	}
}

void Gameboard::drawGraphics()
{
	system("cls");
	gotoxy(10,5);
	setcolor(COLOR_RED,COLOR_BLACK);
	cout << m_somename1;
	setcolor(COLOR_WHITE,COLOR_BLACK);
	cout << "		vs.		" ;
	setcolor(COLOR_CYAN,COLOR_BLACK);

	//displays a different message depending on the user's initial title screen input
	//there will always be a player 1 so there is no need to test that condition
	if (getInput() == (char)ONE_PLAYER)
	{
		cout << "   CPU  " ;
		setcolor(COLOR_WHITE,COLOR_BLACK);
	}
	else if (getInput() == (char)TWO_PLAYERS)
	{
		cout << m_somename2;
		setcolor(COLOR_WHITE,COLOR_BLACK);
	}
	gotoxy(10,7);
	cout << "Player 1 controls";
	gotoxy(10,8);
	cout << "Move left 'a'";
	gotoxy(10,9);
	cout << "Move right 'd'";
	gotoxy(10,10);
	cout << "Drop piece 's'";

	gotoxy(40,7);
	cout << "Player 2 controls";
	gotoxy(40,8);
	cout << "Move left 'j'";
	gotoxy(40,9);
	cout << "Move right 'l'";
	gotoxy(40,10);
	cout << "Drop piece 'k'";
}
//		---		INPUT FUNCTIONS			---		//	

void Gameboard::startGame()
{
	//determines whether the game will start with "Player 1 vs. CPU" or "Player 1 vs. Player 2"
	//there will always be a Player 1
	while(!kbhit())
	{
		drawTitleScreen();
	}
	do
	{
	setInput(getch());
	}while(getInput() != (char)ONE_PLAYER && getInput() != (char)TWO_PLAYERS);

	if (getInput() == (char)ONE_PLAYER)
	{
		cout << "Enter your name:";
		getline(cin,m_somename1);

		cout << m_somename1;
		clearBoard();
		drawGraphics();
	}
	else if (getInput() == (char)TWO_PLAYERS)
	{
		cout << "Enter 1st players name:";
		getline(cin,m_somename1);
		cout << "Enter 2nd players name:";
		getline(cin,m_somename2);
		start.setName(m_somename1,m_somename2);
		clearBoard();
		drawGraphics();
	}
	setcolor(COLOR_BLACK, COLOR_WHITE);
}

void Gameboard::handleInput(char input)
{
	//each player has its own input
	//the input changes depending on the m_player member variable
	if (getPlayerNumber() == PLAYER_ONE)
	{
		switch(input)
		{
			//determines how to move the piece based on the user input
			case 'a':	shiftPieceLeft();	break;
			case 'd':   shiftPieceRight();	break;
			case 's':	dropPiece();	break;
		}
	}
	else if (getPlayerNumber() == PLAYER_TWO)
	{
		switch(input)
		{
			case 'j':	shiftPieceLeft();	break;
			case 'l':   shiftPieceRight();	break;
			case 'k':	dropPiece();	break;
		}
	}
}

//		---		MAIN LOOP		---		//

void Gameboard::gameLoop()
{
	p1.setTurnSuccess(false);

	//the game loop for player 1
	setPlayerNumber(PLAYER_ONE);
	piece.setColor(COLOR_RED);
	piece.setColumnPosition(STARTING_POSITION);
	drawPiece();
	drawBoard();

	//this loop executes as long as the player hasn't dropped a piece
	//dropping a piece is activated when a player presses 's'(player 1) or 'k' (player 2)
	do
	{
		p1.setPlayerInput(getch());
		handleInput(p1.getPlayerInput());
		drawPiece();
		drawBoard();
		gameWin();
	}
	while(!p1.getTurnSuccess());

	p2.setTurnSuccess(false);

	//executes the game loop for player 2 if the initial title screen selection was "2 Players"
	if (!gameFinished())
	{
		setPlayerNumber(PLAYER_TWO);
		piece.setColor(COLOR_CYAN);
		piece.setColumnPosition(STARTING_POSITION);
		drawPiece();
		drawBoard();

		//this loop executes as long as the player hasn't dropped a piece
		//dropping a piece is activated when a player presses 's'(player 1) or 'k' (player 2)
		if (getInput() == (char)TWO_PLAYERS)//added by Earsell
		{
			do
			{
				p2.setPlayerInput(getch());
				handleInput(p2.getPlayerInput());
				drawPiece();
				drawBoard();
				gameWin();
			}
			while(!p2.getTurnSuccess());
		}
		else
		{
			// the ai will move when the player selects "One Player"
			cpu.randomStrategy();//added by Earsell
			piece.setColumnPosition(cpu.getMove());//added by Earsell
			drawPiece();//added by Earsell
			dropPiece();//added by Earsell
			drawBoard();//added by Earsell
			gameWin();//added by Earsell
		}
	}

}
//		---		LOGIC FUNCTIONS		---	//

void Gameboard::shiftPieceLeft()
{
	
	//checks to see if the piece is in bounds or not
	if (piece.getColumnPosition() > ZERO)
	{
		PlaySound(TEXT("Bullet.wav"), NULL, SND_FILENAME);
		piece.setColumnPosition(piece.getColumnPosition() - 1);
	}
}

void Gameboard::shiftPieceRight()
{
	
	//checks to see if the piece is in bounds or not
	if (piece.getColumnPosition() < (BOARD_WIDTH - 1))
	{
		PlaySound(TEXT("Bullet.wav"), NULL, SND_FILENAME);
		piece.setColumnPosition(piece.getColumnPosition() + 1);
	}
}

void Gameboard::dropPiece()
{
	int c = piece.getColumnPosition();
	int r = ZERO;

	if (m_board[r][c] != piece.getSymbol())
	{
		//drops the piece until it collides with another piece or hits the bottom of the board
		while(r < (BOARD_HEIGHT-1) && m_board[r+1][c] != piece.getSymbol())
		{
			r++;
		}
		m_board[r][c] = piece.getSymbol();
		m_colorMap[r][c] = piece.getColor();
		PlaySound(TEXT("BOMB.wav"), NULL, SND_FILENAME);

		//ends the player's turn
		if (getPlayerNumber() == PLAYER_ONE)
		{
			p1.setTurnSuccess(true);
		}
		else if (getPlayerNumber() == PLAYER_TWO)
		{
			p2.setTurnSuccess(true);
		}
		//the ai tracks where the player dropped the piece last if the game is played as "One player"
		if (getInput() == (char)ONE_PLAYER)//added by Earsell
		{
			cpu.trackPlayerMove(r,c);//added by Earsell
		}
	}
}

void Gameboard::drawPiece()
{
	initializeColorMap();
	//each player will have a different set color(i.e. p1 = red, p2 = cyan)
	if (getPlayerNumber() == PLAYER_ONE)
	{
		setcolor(piece.getColor(),COLOR_BLACK);
	}
	else if (getPlayerNumber() == PLAYER_TWO)
	{
		setcolor(piece.getColor(),COLOR_BLACK);
	}

	//clears out the entire array before redrawing the piece in it's new position
	for (int c = 0; c < BOARD_WIDTH; c++)
	{
		piecePositionArray[c] = ' ';
	}

	//places the piece symbol in the array based on column position
	piecePositionArray[piece.getColumnPosition()] = piece.getSymbol();

	// shows where the player selects a column to drop the piece
	for(int c = 0; c < BOARD_WIDTH; c++)
	{
		gotoxy(31+c,20);
		cout << piecePositionArray[c];
	}


	for(int i = 0; i < BOARD_HEIGHT; i++)
	{
		if(m_board[i][piece.getColumnPosition()] == '.')
		{
			m_colorMap[i][piece.getColumnPosition()] = COLOR_YELLOW;
		}
	}
	setcolor(COLOR_WHITE,COLOR_BLACK);
}


void Gameboard::gameWin()
{
	//checks for 4 in a row horizontally
	for (int r = ZERO; r < BOARD_HEIGHT; r++)
	{
		for (int c = ZERO; c < BOARD_WIDTH; c++)
		{
			//uses the color map to detect the right pieces for the right player
			// i.e. red spot = player 1 piece
			// blue spot = player 2 or ai piece
			if(m_colorMap[r][c] == COLOR_RED)
			{
				p1.setPieceCount(p1.getPieceCount()+1);
				p2.setPieceCount(ZERO);
			}
			else if(m_colorMap[r][c] == COLOR_CYAN)
			{
				p2.setPieceCount(p2.getPieceCount()+1);
				p1.setPieceCount(ZERO);
			}
			else
			{
				p1.setPieceCount(ZERO);
				p2.setPieceCount(ZERO);
			}
			//checks for a win after every count
			checkWinStatus();
		}
		p1.setPieceCount(ZERO);
		p2.setPieceCount(ZERO);
	}

	//checks for 4 in a row vertically
	for (int c = ZERO; c < BOARD_WIDTH; c++)
	{
		for (int r = ZERO; r < BOARD_HEIGHT; r++)
		{
			if(m_colorMap[r][c] == COLOR_RED)
			{
				p1.setPieceCount(p1.getPieceCount()+1);
				p2.setPieceCount(ZERO);
			}
			else if(m_colorMap[r][c] == COLOR_CYAN)
			{
				p2.setPieceCount(p2.getPieceCount()+1);
				p1.setPieceCount(ZERO);
			}
			else
			{
				p1.setPieceCount(ZERO);
				p2.setPieceCount(ZERO);
			}
			checkWinStatus();
		}
		p1.setPieceCount(ZERO);
		p2.setPieceCount(ZERO);
	}

	//---		each of the following "for" loops uses an offset		---
	//---		to determine where to starting counting diagonally		---
	//---		on the game board										---

	//checks for 4 in a row diagonally (from left corner)

	for (int i = STARTING_VERTICAL_OFFSET; i >= ZERO; i--)
	{
		//goes through the array in a diagonal fashion and stops at the bottom of the board
		for (int c = ZERO, r = ZERO; (r+i) < BOARD_HEIGHT; c++, r++)
		{
			if(m_colorMap[r+i][c] == COLOR_RED)
			{
				p1.setPieceCount(p1.getPieceCount()+1);
				p2.setPieceCount(ZERO);
			}
			else if(m_colorMap[r+i][c] == COLOR_CYAN)
			{
				p2.setPieceCount(p2.getPieceCount()+1);
				p1.setPieceCount(ZERO);
			}
			else
			{
				p1.setPieceCount(ZERO);
				p2.setPieceCount(ZERO);
			}
			checkWinStatus();
		}
		p1.setPieceCount(ZERO);
		p2.setPieceCount(ZERO);
	}

	//had to break this up until 2 loops because of the diagonals' starting positions
	//shift from vertical to horizontal
	for (int i = STARTING_HORIZONTAL_OFFSET; i <= ENDING_HORIZONTAL_OFFSET; i++)
	{
		//goes through the array in a diagonal fashion and stops at the right of the board
		for (int c = ZERO, r = ZERO; (c+i) < BOARD_WIDTH; c++, r++)
		{
			if(m_colorMap[r][c+i] == COLOR_RED)
			{
				p1.setPieceCount(p1.getPieceCount()+1);
				p2.setPieceCount(ZERO);
			}
			else if(m_colorMap[r][c+i] == COLOR_CYAN)
			{
				p2.setPieceCount(p2.getPieceCount()+1);
				p1.setPieceCount(ZERO);
			}
			else
			{
				p1.setPieceCount(ZERO);
				p2.setPieceCount(ZERO);
			}
			checkWinStatus();
		}
		p1.setPieceCount(ZERO);
		p2.setPieceCount(ZERO);
	}

	//checks for 4 in a row diagonally (from right corner)

	for (int i = STARTING_HORIZONTAL_OFFSET; i >= ZERO; i--)
	{
		//goes through the array in a diagonal fashion and stops at the bottom of the board
		for (int c = BOARD_WIDTH, r = ZERO; (r+i) < BOARD_HEIGHT; c--, r++)
		{
			if(m_colorMap[r+i][c] == COLOR_RED)
			{
				p1.setPieceCount(p1.getPieceCount()+1);
				p2.setPieceCount(ZERO);
			}
			else if(m_colorMap[r+i][c] == COLOR_CYAN)
			{
				p2.setPieceCount(p2.getPieceCount()+1);
				p1.setPieceCount(ZERO);
			}
			else
			{
				p1.setPieceCount(ZERO);
				p2.setPieceCount(ZERO);
			}
			checkWinStatus();
		}
		p1.setPieceCount(ZERO);
		p2.setPieceCount(ZERO);
	}

	//had to break this up until 2 loops because of the diagonals' starting positions
	//shift from vertical to horizontal
	for (int i = STARTING_HORIZONTAL_OFFSET; i <= ENDING_HORIZONTAL_OFFSET; i++)
	{
		//goes through the array in a diagonal fashion and stops at the left of the board
		for (int c = BOARD_WIDTH, r = ZERO; (c-i) >= ZERO; c--, r++)
		{
			if(m_colorMap[r][c-i] == COLOR_RED)
			{
				p1.setPieceCount(p1.getPieceCount()+1);
				p2.setPieceCount(ZERO);
			}
			else if(m_colorMap[r][c-i] == COLOR_CYAN)
			{
				p2.setPieceCount(p2.getPieceCount()+1);
				p1.setPieceCount(ZERO);
			}
			else
			{
				p1.setPieceCount(ZERO);
				p2.setPieceCount(ZERO);
			}
			checkWinStatus();
		}
		p1.setPieceCount(ZERO);
		p2.setPieceCount(ZERO);
	}
}

void Gameboard::checkWinStatus()
{
	//basically sets a boolean variable that lets the gameworld know when a player has won the game
	if (p1.getPieceCount() == WINNER)
	{
		p1.setPlayerWin(true);
	}
	else if (p2.getPieceCount() == WINNER)
	{
		p2.setPlayerWin(true);
	}
}

bool Gameboard::gameFinished()
{
	int gameFinished;
	// determines which player wins
	if (p1.getPlayerWin())
	{
		gotoxy(27,10);
		setcolor(COLOR_RED,COLOR_BLACK);
		cout << "Player 1 Wins!!!";
		setcolor(COLOR_WHITE,COLOR_BLACK);
		gameFinished = endGame();
		if (gameFinished == ZERO)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	if (p2.getPlayerWin())
	{
		if (getInput() == (char)ONE_PLAYER)
		{
			gotoxy(27,10);
			setcolor(COLOR_CYAN,COLOR_BLACK);
			cout << "CPU Wins!!!";
			setcolor(COLOR_WHITE,COLOR_BLACK);
			gameFinished = endGame();
			if (gameFinished == ZERO)
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		else
		{
			gotoxy(27,10);
			setcolor(COLOR_CYAN,COLOR_BLACK);
			cout << "Player 2 Wins!!!";
			setcolor(COLOR_WHITE,COLOR_BLACK);
			gameFinished = endGame();
			if (gameFinished == ZERO)
			{
				return true;
			}
			else
			{
				return false;
			}
		}
	}
}

int Gameboard::endGame()
{
	gotoxy(27,11);
	cout << "Do you want to play again?   'y' = yes		'n' = no";
	do
	{
		setGameInput(getch());
	}while (getGameInput() != 'y' || getGameInput() != 'n');
	if (getGameInput() == 'y')
	{
		//  1 means that the game is not over and the player wants to play again
		return 1;
	}
	else
	{
		//  0 means that the game is over and the player is done
		return 0;
	}
}